import {
  computed,
  getCurrentInstance,
  nextTick,
  reactive,
  ref,
  toRaw,
  unref,
  watchEffect,
} from 'vue'

import { tryOnUnmounted } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import { isFunction } from 'lodash-es'

import type { Fn, Nullable } from '@/types/global'

import type {
  BasicDialogProps,
  ModalMethods,
  ReturnMethods,
  UseDialogInnerReturnType,
  UseModalReturnType,
} from '../types'

const dataTransfer = reactive<any>({})
const visibleData = reactive<{ [key: number]: boolean }>({})

export function useDialog(): UseModalReturnType {
  const modal = ref<Nullable<ModalMethods>>(null)
  const uid = ref<string>('')

  function register(modalMethod: ModalMethods, uuid: string) {
    // console.log("uuid", uuid)
    if (!getCurrentInstance()) {
      throw new Error('useDialog() can only be used inside setup() or functional components!')
    }
    uid.value = uuid
    modal.value = modalMethod
    // 创建函数
    modalMethod.emitVisible = (visible: boolean, uidd: number) => {
      visibleData[uidd] = visible
    }
  }

  const getInstance = () => {
    const instance = unref(modal)
    if (!instance) {
      ElMessage({
        message: '获取dialog实例失败！',
        type: 'error',
        duration: 2000,
      })
    }
    return instance
  }

  const methods: ReturnMethods = {
    setModalProps: (props: Partial<BasicDialogProps>): void => {
      getInstance()?.setModalProps(props)
    },

    getVisible: computed((): boolean => {
      return visibleData[Math.trunc(unref(uid) as unknown as number)] as boolean
    }),

    openDialog: <T = any>(visible = true, data?: T, openOnSet = true): void => {
      // console.log("open", visible)
      getInstance()?.setModalProps({
        dialogVisible: visible,
      })

      if (!data) return
      const id = unref(uid)
      if (openOnSet) {
        dataTransfer[id] = null
        dataTransfer[id] = toRaw(data)
      }
    },

    closeModal: () => {
      getInstance()?.setModalProps({ dialogVisible: false })
    },
  }
  return [register, methods]
}

export const useDialogInner = (callbackFn?: Fn): UseDialogInnerReturnType => {
  const modalInstanceRef = ref<Nullable<ModalMethods>>(null)
  const currentInstance = getCurrentInstance()
  const uidRef = ref<string>('')

  const register = (modalInstance: ModalMethods, uuid: string) => {
    // 未加载时处理
    tryOnUnmounted(() => {
      modalInstanceRef.value = null
    })
    uidRef.value = uuid
    modalInstanceRef.value = modalInstance
    currentInstance?.emit('register', modalInstance, uuid)
  }

  watchEffect(() => {
    const data = dataTransfer[unref(uidRef)]
    if (!data) return
    if (!callbackFn || !isFunction(callbackFn)) return
    nextTick(() => {
      callbackFn(data)
    })
  })
  const getInstance = () => {
    const instance = unref(modalInstanceRef)
    if (!instance) {
      ElMessage({
        message: '获取dialog实例失败！',
        type: 'error',
        duration: 2000,
      })
    }
    return instance
  }
  return [
    register,
    {
      getVisible: computed((): boolean => {
        return visibleData[Math.trunc(unref(uidRef) as unknown as number)] as boolean
      }),

      changeOkLoading: (loading = true) => {
        getInstance()?.setModalProps({ confirmLoading: loading })
      },

      closeModal: () => {
        getInstance()?.setModalProps({ dialogVisible: false })
      },

      setModalProps: (props: Partial<BasicDialogProps>) => {
        getInstance()?.setModalProps(props)
      },
    },
  ]
}
